MapStruct文档(四)

您所在的位置:网站首页 java string转换成日期 MapStruct文档(四)

MapStruct文档(四)

2023-12-24 15:44| 来源: 网络整理| 查看: 265

目录

 

3.1、隐式转换

3.1.1、枚举、BigDecimal、Date、Timestamp

3.1.2、LocalDateTime

3.1.3、Boolean

3.2、*对象属性转换

3.3、将映射目标类型传递给自定义映射器

3.4、将上下文或状态对象传递给自定义方法

3.5、区别相同参数类型和返回类型的映射方法

3.1、隐式转换 enum和StringBigDecimal(等)、基本数据类(包括包装类)和Stringjava.time.LocalDateTime(等)和Stringjava.util.Date、和String

java.sql.Timestamp和java.util.Date

3.1.1、枚举、BigDecimal、Date、Timestamp @Data public class TransformPO { private LevelEnum level; private BigDecimal price; private Date date; private Timestamp timestamp; } @Data public class TransformBO { private String level; private int price; private String date; private Date timestamp; } @Mapper public interface TestMapper { TransformBO toTransformBO(TransformPO transformPO); } @Component public class TestMapperImpl implements TestMapper { @Override public TransformBO toTransformBO(TransformPO transformPO) { if ( transformPO == null ) { return null; } TransformBO transformBO = new TransformBO(); // enum->String if ( transformPO.getLevel() != null ) { transformBO.setLevel( transformPO.getLevel().name() ); } // BigDecimal->int if ( transformPO.getPrice() != null ) { transformBO.setPrice( transformPO.getPrice().intValue() ); } // Date->String if ( transformPO.getDate() != null ) { transformBO.setDate( new SimpleDateFormat().format( transformPO.getDate() ) ); } // Timestamp->Date transformBO.setTimestamp( transformPO.getTimestamp() ); return transformBO; } } TransformPO transformPO = new TransformPO(); transformPO.setLevel(LevelEnum.PERFECT); transformPO.setPrice(new BigDecimal("12.4")); transformPO.setDate(new Date(System.currentTimeMillis())); transformPO.setTimestamp(new Timestamp(System.currentTimeMillis())); System.out.println(testMapper.toTransformBO(transformPO));

结果

Date转String默认使用SimpleDateFormat格式化,@Mapping#dateFormat可以指定格式。

@Mapper public interface TestMapper { @Mapping(target = "date", dateFormat = "yyyy-MM-dd HH:mm:ss") TransformBO toTransformBO(TransformPO transformPO); } @Component public class TestMapperImpl implements TestMapper { @Override public TransformBO toTransformBO(TransformPO transformPO) { if ( transformPO == null ) { return null; } TransformBO transformBO = new TransformBO(); if ( transformPO.getDate() != null ) { transformBO.setDate( new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ).format( transformPO.getDate() ) ); } if ( transformPO.getLevel() != null ) { transformBO.setLevel( transformPO.getLevel().name() ); } if ( transformPO.getPrice() != null ) { transformBO.setPrice( transformPO.getPrice().intValue() ); } transformBO.setTimestamp( transformPO.getTimestamp() ); return transformBO; } }

结果

 

3.1.2、LocalDateTime @Data public class TransformPO { private String level; private float price; private String date; private LocalDateTime localDateTime; private Date timestamp; } @Data public class TransformBO { private LevelEnum level; private String price; private Date date; private String localDateTime; private Timestamp timestamp; } @Mapper public interface TestMapper { @Mapping(target = "localDateTime", dateFormat = "yyyy-MM-dd HH:mm:ss") @Mapping(target = "date", dateFormat = "yyyy-MM-dd HH:mm") @Mapping(target = "price", numberFormat = "$#.00") TransformBO toTransformBO(TransformPO transformPO); } @Component public class TestMapperImpl implements TestMapper { @Override public TransformBO toTransformBO(TransformPO transformPO) { if ( transformPO == null ) { return null; } TransformBO transformBO = new TransformBO(); // LocalDateTime->String if ( transformPO.getLocalDateTime() != null ) { transformBO.setLocalDateTime( DateTimeFormatter.ofPattern( "yyyy-MM-dd HH:mm:ss" ).format( transformPO.getLocalDateTime() ) ); } // String->Date try { if ( transformPO.getDate() != null ) { transformBO.setDate( new SimpleDateFormat( "yyyy-MM-dd HH:mm" ).parse( transformPO.getDate() ) ); } } catch ( ParseException e ) { throw new RuntimeException( e ); } // 基本类型->String transformBO.setPrice( new DecimalFormat( "$#.00" ).format( transformPO.getPrice() ) ); // String->enum if ( transformPO.getLevel() != null ) { transformBO.setLevel( Enum.valueOf( LevelEnum.class, transformPO.getLevel() ) ); } // Date->Timestamp if ( transformPO.getTimestamp() != null ) { transformBO.setTimestamp( new Timestamp( transformPO.getTimestamp().getTime() ) ); } return transformBO; } } TransformPO transformPO = new TransformPO(); transformPO.setLevel("PERFECT"); transformPO.setPrice(12.4f); transformPO.setDate("2020-10-29 13:56"); transformPO.setLocalDateTime(LocalDateTime.now()); transformPO.setTimestamp(new Date(System.currentTimeMillis())); System.out.println(testMapper.toTransformBO(transformPO));

结果

基本类型、包装类、BigDecimal转String默认使用DecimalFormat格式化,@Mapping#numberFormat可以指定格式。

 

3.1.3、Boolean @Data public class TransformPO { private String price; private Float discount; private Long count; private Boolean delete; private String localDateTime; } @Data public class TransformBO { private BigDecimal price; private BigDecimal discount; private long count; private String delete; private LocalDateTime localDateTime; } @Mapper public interface TestMapper { @Mapping(target = "localDateTime", dateFormat = "yyyy-MM-dd HH") TransformBO toTransformBO(TransformPO transformPO); } @Component public class TestMapperImpl implements TestMapper { @Override public TransformBO toTransformBO(TransformPO transformPO) { if ( transformPO == null ) { return null; } TransformBO transformBO = new TransformBO(); if ( transformPO.getLocalDateTime() != null ) { transformBO.setLocalDateTime( LocalDateTime.parse( transformPO.getLocalDateTime(), DateTimeFormatter.ofPattern( "yyyy-MM-dd HH" ) ) ); } if ( transformPO.getPrice() != null ) { transformBO.setPrice( new BigDecimal( transformPO.getPrice() ) ); } if ( transformPO.getDiscount() != null ) { transformBO.setDiscount( BigDecimal.valueOf( transformPO.getDiscount() ) ); } if ( transformPO.getCount() != null ) { transformBO.setCount( transformPO.getCount() ); } if ( transformPO.getDelete() != null ) { transformBO.setDelete( String.valueOf( transformPO.getDelete() ) ); } return transformBO; } } TransformPO transformPO = new TransformPO(); transformPO.setPrice("12.3"); transformPO.setDiscount(20.3f); transformPO.setDelete(false); transformPO.setLocalDateTime("2020-10-29 14"); System.out.println(testMapper.toTransformBO(transformPO));

结果

 

float转BigDecimal也是有精度丢失问题,还是建议String转BigDecimal。

更详细的请参考mapstruct类型转换。

3.2、*对象属性转换 @Mapper public interface TestMapper { TestBO toTestBO(TestPO testPO); TestThreeBO toTestThreeBO(TestThreePO testThreePO); } @Component public class TestMapperImpl implements TestMapper { @Override public TestBO toTestBO(TestPO testPO) { if ( testPO == null ) { return null; } TestBO testBO = new TestBO(); testBO.setId( testPO.getId() ); testBO.setName( testPO.getName() ); testBO.setPrice( testPO.getPrice() ); testBO.setCreteTime( testPO.getCreteTime() ); return testBO; } @Override public TestThreeBO toTestThreeBO(TestThreePO testThreePO) { if ( testThreePO == null ) { return null; } TestThreeBO testThreeBO = new TestThreeBO(); testThreeBO.setTest( toTestBO( testThreePO.getTest() ) ); return testThreeBO; } } TestPO testPO = new TestPO(); testPO.setId(1L); testPO.setName("haru"); testPO.setCreteTime(new Date(System.currentTimeMillis())); TestThreePO testThreePO = new TestThreePO(); testThreePO.setTest(testPO); System.out.println(testMapper.toTestThreeBO(testThreePO));

结果

 

@MappingConfig,@Mapper,@BeanMapping,@Mapping注解可以设置mappingControl,越往后的优先级越高,默认值是MappingControl.class,还有NoComplexMapping.class、DeepClone.class,用于控制每个字段属性映射的方式;MappingControl.class支持

1、MappingControl.Use.DIRECT——直接复制具有相同属性类型的字段,但如果有自定义的映射配置@Mapping和导入了其他Mapper的自定义的映射,会将直接赋值覆盖;自定义的映射配置@Mapping优先级高于导入了其他Mapper的自定义的映射。

2、MappingControl.Use.MAPPING_METHOD——属性类型不同的字段,会去查找将源属性的类型作为参数,将目标属性的类型作为返回的映射方法(包括自定义方法、抽象类实现方法和接口默认方法)。

3、MappingControl.Use.BUILT_IN_CONVERSION——如果不存在上述方法,查找内置转换方法,就像BigDecimal转String。

4、MappingControl.Use.COMPLEX_MAPPING——如果内置转换方法不存在,将进行一些复杂转换,也就是结合现有的映射方法和内置转换,互相嵌套生成一个能够映射的方法。

5、如果都没有,则会自动生成子映射方法,就像上面的例子若是不指定TestPO到TestBO的接口方法,则也会主动生成。

6、若这也没法生成则编译就会报错了。

@Mapper public interface TestMapper { TestThreeBO toTestThreeBO(TestThreePO testThreePO); } @Component public class TestMapperImpl implements TestMapper { @Override public TestThreeBO toTestThreeBO(TestThreePO testThreePO) { if ( testThreePO == null ) { return null; } TestThreeBO testThreeBO = new TestThreeBO(); testThreeBO.setTest( testPOToTestBO( testThreePO.getTest() ) ); return testThreeBO; } // 自动生成 protected TestBO testPOToTestBO(TestPO testPO) { if ( testPO == null ) { return null; } TestBO testBO = new TestBO(); testBO.setId( testPO.getId() ); testBO.setName( testPO.getName() ); testBO.setPrice( testPO.getPrice() ); testBO.setCreteTime( testPO.getCreteTime() ); return testBO; } }

NoComplexMapping.class支持除MappingControl.Use.COMPLEX_MAPPING其他三种,DeepClone.class只支持MappingControl.Use.MAPPING_METHOD。

通常我们不需要修改这个属性。

举个例子

引用3.1.3、DEMO3,将其mapper修改为,使用DeepClone的mappingControl,这样我们就只能进行MappingControl.Use.MAPPING_METHOD映射了。

@Mapper(mappingControl = DeepClone.class) public interface TestMapper { @Mapping(target = "localDateTime", dateFormat = "yyyy-MM-dd HH") TransformBO toTransformBO(TransformPO transformPO); }

编译结果,TransformPO中的localDateTime是String没法转换TransformBO中LocalDateTime的localDateTime了,不满足MappingControl.Use.DIRECT,所有进行MappingControl.Use.MAPPING_METHOD判断,也不满足,又不支持MappingControl.Use.BUILT_IN_CONVERSION和MappingControl.Use.COMPLEX_MAPPING,也无法生成子映射,只能报错了。

NoComplexMapping.class、DeepClone.class还在试验阶段。

3.3、将映射目标类型传递给自定义映射器

就是说在使用@Mapper#uses()时,使用的自定义映射器中的方法可以接受Class对象,要使用 @TargetType标注。

@Mapper(uses = {BaseMapper.class}) public interface TestMapper { TestSevenBO testToBO(TestFivePO testPO); } @Mapper public class BaseMapper { public T testToBO(BasePO basePO, @TargetType Class baseBOClass) { try { T t = baseBOClass.newInstance(); t.setId(basePO.getId()); return t; } catch (Exception e) { return null; } } } @Component public class TestMapperImpl implements TestMapper { @Autowired private BaseMapper baseMapper; @Override public TestSevenBO testToBO(TestFivePO testPO) { if ( testPO == null ) { return null; } TestSevenBO testSevenBO = new TestSevenBO(); testSevenBO.setTest( baseMapper.testToBO( testPO.getTest(), TestSixBO.class ) ); return testSevenBO; } } TestFivePO testFivePO = new TestFivePO(); TestFourPO testFourPO = new TestFourPO(); testFourPO.setId(1L); testFivePO.setTest(testFourPO); System.out.println(testMapper.testToBO(testFivePO));

结果

3.4、将上下文或状态对象传递给自定义方法

@Context标注是上下文或状态对象,这样在生成映射方法时就会调用@Context标注的参数的方法,映射方法和自定义方法参数都需要@Context标注参数。

@Data public class ThreadLocalContext { private ThreadLocal threadLocal; public ThreadLocalContext() { threadLocal = new ThreadLocal(); } } @Mapper public class BaseMapper { public TestSixBO toTestSixBOWithContext(TestFourPO testFourPO, @Context ThreadLocalContext threadLocalContext) { TestSixBO testBO = new TestSixBO(); testBO.setId(testFourPO.getId()); testBO.setName((String) threadLocalContext.getThreadLocal().get()); return testBO; } } @Mapper(uses = {BaseMapper.class}) public interface TestMapper { TestSevenBO testToBO(TestFivePO testPO, @Context ThreadLocalContext threadLocalContext); } @Component public class TestMapperImpl implements TestMapper { @Autowired private BaseMapper baseMapper; @Override public TestSevenBO testToBO(TestFivePO testPO, ThreadLocalContext threadLocalContext) { if ( testPO == null ) { return null; } TestSevenBO testSevenBO = new TestSevenBO(); testSevenBO.setTest( baseMapper.toTestSixBOWithContext( testPO.getTest(), threadLocalContext ) ); return testSevenBO; } } ThreadLocalContext threadLocalContext = new ThreadLocalContext(); threadLocalContext.getThreadLocal().set("xx"); TestFivePO testFivePO = new TestFivePO(); TestFourPO testFourPO = new TestFourPO(); testFourPO.setId(1L); testFivePO.setTest(testFourPO); System.out.println(testMapper.testToBO(testFivePO, threadLocalContext));

结果

3.5、区别相同参数类型和返回类型的映射方法 @Mapper public class BaseMapper { public String toString1(String name) { return name + "1"; } public String toString2(String name) { return name + "2"; } } @Mapper(uses = {BaseMapper.class}) public interface TestMapper { TestSixBO testToBO(TestFourPO testPO); }

toString1、toString2方法的参数类型和返回类型相同,编译直接报错。

所以可以使用@Qualifier来区分。

@Qualifier @Target(ElementType.METHOD) @Retention(RetentionPolicy.CLASS) public @interface StringToString1 { } @Qualifier @Target(ElementType.METHOD) @Retention(RetentionPolicy.CLASS) public @interface StringToString2 { } @Mapper(uses = {BaseMapper.class}) public interface TestMapper { @Mapping(target = "name", qualifiedBy = {StringToString1.class}) TestSixBO testToBO(TestFourPO testPO); } @Mapper public class BaseMapper { @StringToString1 public String toString1(String name) { return name + "1"; } @StringToString2 public String toString2(String name) { return name + "2"; } } @Component public class TestMapperImpl implements TestMapper { @Autowired private BaseMapper baseMapper; @Override public TestSixBO testToBO(TestFourPO testPO) { if ( testPO == null ) { return null; } TestSixBO testSixBO = new TestSixBO(); // 使用qualifiedBy中设置的注解的方法 testSixBO.setName( baseMapper.toString1( testPO.getName() ) ); testSixBO.setId( testPO.getId() ); return testSixBO; } }

自定义的@Qualifier的@Target还可以设为TYPE。

@Qualifier @Target(ElementType.TYPE) @Retention(RetentionPolicy.CLASS) public @interface StringToString1 { } @Qualifier @Target(ElementType.TYPE) @Retention(RetentionPolicy.CLASS) public @interface StringToString2 { } @Mapper @StringToString1 public class BaseMapper { public String toString1(String name) { return name + "1"; } } @Mapper @StringToString2 public class BaseMapper2 { public String toString2(String name) { return name + "2"; } } @Mapper(uses = {BaseMapper.class, BaseMapper2.class}) public interface TestMapper { @Mapping(target = "name", qualifiedBy = {StringToString2.class}) TestSixBO testToBO(TestFourPO testPO); } @Component public class TestMapperImpl implements TestMapper { @Autowired private BaseMapper2 baseMapper2; @Override public TestSixBO testToBO(TestFourPO testPO) { if ( testPO == null ) { return null; } TestSixBO testSixBO = new TestSixBO(); // 只使用qualifiedBy中设置的注解的类中的方法 testSixBO.setName( baseMapper2.toString2( testPO.getName() ) ); testSixBO.setId( testPO.getId() ); return testSixBO; } }

还可以使用@Named取代定义一个@Qualifier的接口。

@Mapper @Named("StringToString1") public class BaseMapper { public String toString1(String name) { return name + "1"; } } @Mapper @Named("StringToString2") public class BaseMapper2 { public String toString2(String name) { return name + "2"; } } @Mapper(uses = {BaseMapper.class, BaseMapper2.class}) public interface TestMapper { @Mapping(target = "name", qualifiedByName = {"StringToString2"}) TestSixBO testToBO(TestFourPO testPO); } @Component public class TestMapperImpl implements TestMapper { @Autowired private BaseMapper2 baseMapper2; @Override public TestSixBO testToBO(TestFourPO testPO) { if ( testPO == null ) { return null; } TestSixBO testSixBO = new TestSixBO(); testSixBO.setName( baseMapper2.toString2( testPO.getName() ) ); testSixBO.setId( testPO.getId() ); return testSixBO; } }

注意:若类上注解了@Named,mapper中引入了此类,要想使用引入类中自定义的映射方法,映射字段时就必须指定qualifiedByName。

@Mapper @Named("baseMapper") public class BaseMapper { public String toString(String s) { return s; } public String toDateString(Date date) { return date.toString(); } } @Mapper(uses = {BaseMapper.class}) public interface TestMapper { BaseBO toTestBO(BasePO basePO); } @Component public class TestMapperImpl implements TestMapper { @Override public BaseBO toTestBO(BasePO basePO) { if ( basePO == null ) { return null; } BaseBO baseBO = new BaseBO(); baseBO.setId( basePO.getId() ); baseBO.setName( basePO.getName() ); if ( basePO.getCreateTime() != null ) { baseBO.setCreateTime( new SimpleDateFormat().format( basePO.getCreateTime() ) ); } return baseBO; } }

结果没有使用BaseMapper中的自定义映射。

@Mapper(uses = {BaseMapper.class}) public interface TestMapper { @Mapping(target = "name", qualifiedByName = {"baseMapper"}) BaseBO toTestBO(BasePO basePO); } @Component public class TestMapperImpl implements TestMapper { @Autowired private BaseMapper baseMapper; @Override public BaseBO toTestBO(BasePO basePO) { if ( basePO == null ) { return null; } BaseBO baseBO = new BaseBO(); baseBO.setName( baseMapper.toString( basePO.getName() ) ); baseBO.setId( basePO.getId() ); if ( basePO.getCreateTime() != null ) { baseBO.setCreateTime( new SimpleDateFormat().format( basePO.getCreateTime() ) ); } return baseBO; } }

@BeanMapping#qualifiedBy选择不是字段映射方法,而是对象的工厂方法。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3